﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

namespace FileModelNS
{
	public class FileModel
	{
		// Properties( For File Contents )
		public string FileName { get { return (_FileContents != null ? _FileContents.FileName : string.Empty); } }
		public int Length { get { return (_FileContents != null ? _FileContents.Length : 0); } }
		public byte[] Data { get { return (_FileContents != null ? _FileContents.Data : null); } }
		public bool IsFileLoaded { get { return (_FileContents != null ); } }

		// Properties( For File Format )
		public string FormatFileName { get { return (_FileFormat != null ? _FileFormat.FileName : string.Empty); } }
		// TODO: I like to return an immutable tree! 
		public Tree<FormatNode> Tree { get { return (_FileFormat != null ? _FileFormat.Tree : null); } }

		// Properties( For File Model )
		public FormatNode SelectedFormatNode { get { return _SelectedFormatNode; } }

		// Events
		public event EventHandler FileLoaded;
		public event EventHandler FormatLoaded;
		public event EventHandler FormatUnloaded;
		public event EventHandler SelectedFormatNodeChanged;

		// Attributes
		private FileContents _FileContents;
		private FileFormat _FileFormat;
		private FormatNode _SelectedFormatNode;

		public FileModel()
		{
		}

		public void LoadFile(string path)
		{
			// Unload Format
			_FileFormat = null;
			if (FormatUnloaded != null)
				FormatUnloaded(this, EventArgs.Empty);

			_FileContents = new FileContents(path);
			if (FileLoaded != null)
				FileLoaded(this, EventArgs.Empty);
		}

		public void LoadFormatFile(string path)
		{
			try
			{
				// Load the format xml
				_FileFormat = new FileFormat(path, _FileContents);
				if (FormatLoaded != null)
					FormatLoaded(this, EventArgs.Empty);
			}
			catch( NonHexValueException e )
			{
				new Exception("Signature should be hex\nFor example, 0x424D\n\nCurrent signature: " + e.Value );
			}
		}

		public void SelectFormatNode(string path)
		{
			if ( null == _FileFormat ) throw new Exception( "File Format Not Loaded.");

			var treeNode = _FileFormat.FindPath(path);
			if ( null == treeNode )
				throw new Exception( "Invalid Path.");

			if (treeNode.Value != _SelectedFormatNode)
			{
				_SelectedFormatNode = treeNode.Value;
				if (SelectedFormatNodeChanged != null)
					SelectedFormatNodeChanged(this, EventArgs.Empty);
			}
		}

		public void SelectFormatNode(int offset)
		{
			if (null == _FileFormat) throw new Exception("File Format Not Loaded.");
			Debug.Assert( null != _FileContents );
			if ( offset < 0 || offset >= _FileContents.Length )
				throw new Exception("Invalid Offset");

			var treeNode = _FileFormat.FindOffset(offset);
			if (null == treeNode)
				return;

			if (treeNode.Value != _SelectedFormatNode)
			{
				_SelectedFormatNode = treeNode.Value;
				if (SelectedFormatNodeChanged != null)
					SelectedFormatNodeChanged(this, EventArgs.Empty);
			}
		}

	}
}
